(* Programme principal *)

open Format
open Lexing
open Lexer
open Parser
open Ast
open Typer
open Compile

let usage = "usage: compilo [options] file.c"

let parse_only = ref false
let type_only = ref false

let spec =
  [
    "-parse-only", Arg.Set parse_only, "  Pour ne faire uniquement la phase d'analysesyntaxique";
    "-type_only", Arg.Set type_only, "  Pour ne pas faire la phase de typage et les phases suivantes";
  ]

(* verifie l'existance du fichier passe en parametre et son extension *)
let file =
  let file = ref None in
  let set_file s =
    if not (Filename.check_suffix s ".c") then
      raise (Arg.Bad "no .c extension");
    file := Some s
  in
  Arg.parse spec set_file usage;
  match !file with 
    Some f -> f | None -> Arg.usage spec usage; exit 1

(* Permet de reporter une location dans le fichier compile *)
let report_loc (b,e) = 
  let l = b.pos_lnum in
  let fc = b.pos_cnum - b.pos_bol + 1 in
  let lc = e.pos_cnum - b.pos_bol + 1 in
  printf "File \"%s\", line %d, characters %d-%d:\n" file l fc lc


let () =
  let c = open_in file in
        printf "lexing...\n";
  let lb = Lexing.from_channel c in
        printf "lexed !\n";
  try
        printf "parsing...\n";
    let p = Parser.file Lexer.token lb in
        printf "parsed !\n";
    close_in c;
    if !parse_only then exit 0;
        printf "typing...\n";
	let p = Typer.typer_fichier p in
        printf "typed !\n";
	if !type_only then exit 0;
        printf "compiling...\n";
	let c = Compile.compile_file p in
        printf "compiled !\n";
    let output_file = (Filename.chop_suffix file ".c") ^ ".s" in
    let out = open_out output_file in
    let outf = formatter_of_out_channel out in
    Mips.print_program outf c;
    pp_print_flush outf ();
    close_out out;
	exit 0
    (*failwith "Typage non-implémenté"*)
  with
    | Lexical_error s ->
        report_loc (lexeme_start_p lb, lexeme_end_p lb);
        printf "lexical error: %s\n." s;
        exit 1
    | Parsing.Parse_error ->
        report_loc (lexeme_start_p lb, lexeme_end_p lb);
        printf "lyntax error\n.";
        exit 1
    | Typer.Variable_non_trouvee (s, l) ->
		report_loc l;
        printf "lypage error : Variable non Trouve\n.";
        exit 1
	| Typer.Erreur_de_typage (s, l) ->
		report_loc l;
		 printf "lypage error : %s\n" s;
        exit 1
	| Typer.Main_inexistant ->
		 printf "lypage error : Main inexistant\n";
        exit 1
	| Return_mal_type ->
		 printf "lypage error : Return mal lype\n";
        exit 1
    | e -> 
        printf "Anomaly: %s.\n" (Printexc.to_string e);
        exit 2
